package net.yyge.apksigner;

import java.io.*;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipUtils {


    /**
     * 将指定目录压缩为 APK 文件（实际是 ZIP 格式）
     *
     * @param sourceDir 要压缩的目录
     * @return 压缩完成后的 APK 文件对象
     * @throws IOException 如果压缩失败
     */
    public static File zipDir(File sourceDir, File outputFile) throws IOException {
        // 1. 验证输入
        if (sourceDir == null) {
            throw new IllegalArgumentException("源目录不能为 null");
        }
        if (!sourceDir.exists()) {
            throw new FileNotFoundException("源目录不存在: " + sourceDir.getAbsolutePath());
        }
        if (!sourceDir.isDirectory()) {
            throw new IllegalArgumentException("源路径不是目录: " + sourceDir.getAbsolutePath());
        }

        // 2. 获取标准路径（避免路径问题）
        String rootPath = sourceDir.getCanonicalPath().replace('\\', '/');

        // 3. 创建输出 APK 文件（位于源目录的父目录下的 build/apk/ 中）

        if (!outputFile.exists()) {
            if (!outputFile.mkdirs()) {
                throw new IOException("无法创建输出目录: " + outputFile.getAbsolutePath());
            }
        }

        // 如果已存在，先删除
        if (outputFile.exists() && !outputFile.delete()) {
            throw new IOException("无法删除已存在的输出文件: " + outputFile.getAbsolutePath());
        }

        // 4. 开始压缩
        try (FileOutputStream fos = new FileOutputStream(outputFile);
             BufferedOutputStream bos = new BufferedOutputStream(fos);
             ZipOutputStream zos = new ZipOutputStream(bos)) {

            // 启动压缩
            zipFile(sourceDir, rootPath, zos);

            // 强制写入并关闭
            zos.flush();
            bos.flush();
            fos.flush();

        } catch (IOException e) {
            // 压缩失败，删除残余文件
            if (outputFile.exists()) {
                outputFile.delete();
            }
            throw new IOException("压缩失败: " + e.getMessage(), e);
        }

        // 5. 验证结果
        if (!outputFile.exists()) {
            throw new IOException("压缩完成，但输出文件不存在");
        }
        if (outputFile.length() == 0) {
            throw new IOException("压缩完成，但输出文件大小为 0，请检查源目录是否为空");
        }

        System.out.println("✅ 压缩成功: " + outputFile.getAbsolutePath() + " (" + outputFile.length() + " 字节)");
        return outputFile;
    }

    /**
     * 递归压缩文件或目录
     */
    /**
     * 递归压缩文件或目录
     */
    private static void zipFile(File file, String rootPath, ZipOutputStream zos) throws IOException {
        if (file.isDirectory()) {
            File[] children = file.listFiles();
            if (children != null && children.length > 0) {
                for (File child : children) {
                    zipFile(child, rootPath, zos);
                }
            } else {
                // 空目录也需要添加条目
                String dirPath = getRelativePath(file, rootPath) + "/";
                ZipEntry entry = new ZipEntry(dirPath);
                zos.putNextEntry(entry);
                zos.closeEntry();
            }
        } else {
            String entryName = getRelativePath(file, rootPath);
            ZipEntry entry = new ZipEntry(entryName);

            // 👇 关键：如果文件是 resources.arsc，则不压缩
            if ("resources.arsc".equals(file.getName())) {
                entry.setMethod(ZipEntry.STORED); // 不压缩
                entry.setSize(file.length());
                entry.setCompressedSize(file.length()); // 压缩后大小 = 原始大小
                entry.setCrc(computeCrc(file));       // 必须设置 CRC-32 校验码
            } else {
                // 其他文件正常压缩
                entry.setMethod(ZipEntry.DEFLATED);
                entry.setTime(file.lastModified());
                // size, compressedSize, crc 由 ZipOutputStream 自动计算（如果未设置）
            }

            zos.putNextEntry(entry);

            try (FileInputStream fis = new FileInputStream(file);
                 BufferedInputStream bis = new BufferedInputStream(fis)) {
                byte[] buffer = new byte[8192];
                int len;
                while ((len = bis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
            }

            zos.closeEntry();
        }
    }


    /**
     * 计算文件的 CRC32 校验码
     */
    private static long computeCrc(File file) throws IOException {
        CRC32 crc = new CRC32();
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = bis.read(buffer)) > 0) {
                crc.update(buffer, 0, len);
            }
        }
        return crc.getValue();
    }

    /**
     * 计算相对于根目录的路径（使用 / 分隔符）
     */
    private static String getRelativePath(File file, String rootPath) throws IOException {
        String filePath = file.getCanonicalPath().replace('\\', '/');
        if (filePath.startsWith(rootPath)) {
            try {
                 return filePath.substring(rootPath.length() + 1);
            }catch (Exception e){
                return filePath.substring(rootPath.length() );
            }
           // +1 跳过首斜杠
        } else {
            return file.getName(); // 安全兜底
        }
    }
}
